package com.yt.dubbo.filter;

import com.alibaba.fastjson.JSON;
import com.yt.common.bo.HeadParamsBO;
import com.yt.common.constant.CommonParameter;
import com.yt.common.enums.CodeEnum;
import com.yt.common.utils.StrUtils;
import com.yt.dubbo.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;
import org.apache.dubbo.rpc.service.GenericService;

import java.util.HashMap;
import java.util.Map;

//在这里首先你还得理解一个概念，dubbo当中区分一个消费者跟生产者
//在使用dubbo过滤器的时候，我们可以指定当前过滤器是在当前应用处于生产者还是处于消费者时才激活。

//这里的激活注解中的group注意一定要选择 group = {PROVIDER}
//并且这个过滤器的位置要位于order应用当中,这样的话，网关发起的请求打到order
//不论是order应用调用发生异常还是order调用的下层应用发生异常都可以在这里捕捉到。
//@Activate(group = {PROVIDER})

@Slf4j
@Activate(group = {"PROVIDER"}, order = -30000)
public class CommonParameterFilter implements Filter {

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        System.out.println("==dubbo==CommonParameterFilter========:");
        if (RpcContext.getContext().isConsumerSide()) {
            invocation.put("headParamsBO", CommonParameter.getHeadParamsBO());

            try {
                Map<String, String> paramsMap = BeanUtils.describe(CommonParameter.getHeadParamsBO());
                System.out.println("==dubbo==paramsMap========:" + JSON.toJSONString(paramsMap));
                if (paramsMap != null && paramsMap.size() > 0) {
                    for (String key : paramsMap.keySet()) {
                        if (StrUtils.isNotEmpty(paramsMap.get(key))) {
                            invocation.getAttachments().put(key, paramsMap.get(key));
                        }
                    }
                }

            } catch (Exception e) {
                e.printStackTrace();
                log.error("consumer(消费者) is error", e);
            }
            return invoker.invoke(invocation);
        } else {

            HeadParamsBO paramsBO = new HeadParamsBO();
            Map<String, String> paramsMap = invocation.getAttachments();
            if (paramsMap != null && paramsMap.size() > 0) {
                try {
                    BeanUtils.populate(paramsBO, paramsMap);
                    CommonParameter.setHeadParamsBO(paramsBO);
                } catch (Exception e) {
                    e.printStackTrace();
                    log.error("provider(生产者) is error", e);
                }
            }
//            log.info("==dubbo==paramsBO========:" + JSON.toJSONString(paramsBO));
            Result result = invoker.invoke(invocation); // 进行服务调用，那么写在这行代码前面的代码就是在业务代码前拦截了，写在之后的代码就是执行完业务代码后拦截了。
            if (result.hasException() && invoker.getInterface() != GenericService.class) {
                Throwable exception = result.getException();
                result = AsyncRpcResult.newDefaultAsyncResult(buildExceptionResponse(exception), invocation);
                log.error("系统异常参数=异常CommonParameterFilter===>"+ JSON.toJSONString(CommonParameter.getHeadParamsBO()), exception);
                return result;
            }
            return result;
        }
    }

    // 封装业务异常
    private Map<String, Object> buildExceptionResponse(Throwable exception){
        Map<String, Object> result = new HashMap<>();
        if (exception instanceof ServiceException) {
            ServiceException serviceException = (ServiceException)exception;

            result.put("code", serviceException.getCode());
            result.put("msg", serviceException.getMessage());
        } else {
            result.put("code", CodeEnum.FAIL_100005.getCode());
            result.put("msg", CodeEnum.FAIL_100005.getMsg());
        }

        return result;
    }
}
